package com.errol.generic.file.image.service;

import com.renjia.service.generic.file.core.pojo.FileExtension;
import com.renjia.service.generic.file.core.pojo.Filepath;
import com.renjia.service.generic.file.core.service.FileInnerService;
import com.renjia.service.generic.file.core.service.FileService;
import com.renjia.service.generic.log.LogService;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import sun.font.FontDesignMetrics;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.List;

/**
 * Created by Errol on 19/08/07.
 *
 * @author zhang xiao bin
 * @version v1.0
 * @date 2020/10/21
 * @since v4.7.6
 */
@Service
public class ImageServiceImpl implements ImageService {

    private final List<FileExtension> imageExtensions = Arrays.asList(FileExtension.JPEG, FileExtension.PNG, FileExtension.JPG);
    private final FileInnerService fileInnerService;
    private final FileService fileService;
    private final LogService logService;

    public ImageServiceImpl(FileInnerService fileInnerService, FileService fileService, LogService logService) {
        this.fileInnerService = fileInnerService;
        this.fileService = fileService;
        this.logService = logService;
    }

    @Override
    public File writeWordsToImage(@NonNull String words, @NonNull Font font, @NonNull Filepath filepath, @NonNull FileExtension imageExtension, int width, int height) {
        if (!imageExtensions.contains(imageExtension)) {
            throw new RuntimeException("请传入图片类型扩展");
        }
        try {
            BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics2D = bufferedImage.createGraphics();
            graphics2D.setColor(Color.WHITE);
            graphics2D.fillRect(0, 0, width, height);
            graphics2D.setFont(font);
            graphics2D.setColor(Color.BLACK);
            FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
            int w = metrics.stringWidth(words);
            int h = metrics.getHeight() - font.getSize() / 4;
            graphics2D.drawString(words, (width - w) / 2, h + ((height - h) / 2));
            graphics2D.dispose();
            File file = new File(fileInnerService.newRandomFilePath(filepath, imageExtension));
            ImageIO.write(bufferedImage, imageExtension.name().toLowerCase(), file);
            return file;
        } catch (Exception e) {
            logService.error(e);
            return null;
        }
    }

    @Override
    public File rotateImage(File imageFile, int angel) {
        if (imageFile == null) {
            return null;
        }
        try {
            BufferedImage sourceImage = ImageIO.read(imageFile);
            if (angel < 0) {
                // 将负数角度，纠正为正数角度
                angel = angel + 360;
            }
            int imageWidth = sourceImage.getWidth(null);
            int imageHeight = sourceImage.getHeight(null);
            // 计算重新绘制图片的尺寸
            Rectangle rectangle = calculatorRotatedSize(new Rectangle(new Dimension(imageWidth, imageHeight)), angel);
            // 获取原始图片的透明度
            int type = sourceImage.getColorModel().getTransparency();
            BufferedImage newImage = null;
            newImage = new BufferedImage(rectangle.width, rectangle.height, type);
            Graphics2D graphics = newImage.createGraphics();
            // 平移位置
            graphics.translate((rectangle.width - imageWidth) / 2, (rectangle.height - imageHeight) / 2);
            // 旋转角度
            graphics.rotate(Math.toRadians(angel), (double) imageWidth / (double)2, (double)(double)imageHeight / (double)2);
            // 绘图
            graphics.drawImage(sourceImage, null, null);
            // 写入新图片
            FileExtension fileExtension = fileService.getFileExtension(imageFile.getName());
            File newImageFile = new File(fileInnerService.newRandomFilePath(Filepath.TEMP, fileExtension));
            ImageIO.write(newImage, fileExtension.name().toLowerCase(), newImageFile);
            return newImageFile;
        } catch (Exception e) {
            logService.error(e, "旋转图片时异常");
            return null;
        }
    }

    /**
     * 计算旋转后的尺寸
     * @param src 原图尺寸
     * @param angel 旋转角度
     * @return
     */
    private static Rectangle calculatorRotatedSize(Rectangle src, int angel) {
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }
        double r = Math.sqrt((double)src.height * src.height + (double)src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angelAlpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angelDeltaWidth = Math.atan((double) src.height / src.width);
        double angelDeltaHeight = Math.atan((double) src.width / src.height);

        int lenDeltaWidth = (int) (len * Math.cos(Math.PI - angelAlpha - angelDeltaWidth));
        int lenDeltaHeight = (int) (len * Math.cos(Math.PI - angelAlpha - angelDeltaHeight));
        int des_width = src.width + lenDeltaWidth * 2;
        int des_height = src.height + lenDeltaHeight * 2;
        return new Rectangle(new Dimension(des_width, des_height));
    }
}
